/**
 *    Copyright (C) 2008, 2009, 2010 Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_BTREE_FACTORY_HPP
#define	_CUBEFS_CORE_BTREE_FACTORY_HPP

#include <cubefs/core/container/container.hpp>

#include <cubefs/core/btree/names.hpp>
#include <cubefs/core/btree/locators.hpp>

#include <cubefs/core/btree/pages/pages.hpp>

#include <cubefs/core/btree/model/base.hpp>
#include <cubefs/core/btree/model/tools.hpp>
#include <cubefs/core/btree/model/checks.hpp>
#include <cubefs/core/btree/model/init.hpp>
#include <cubefs/core/btree/model/insert.hpp>
#include <cubefs/core/btree/model/remove.hpp>
#include <cubefs/core/btree/model/model_api.hpp>
#include <cubefs/core/btree/model/stubs.hpp>
#include <cubefs/core/btree/model/find.hpp>

#include <cubefs/core/btree/iterator.hpp>

#include <cubefs/core/tools/types/typelist.hpp>
#include <cubefs/core/tools/assert.hpp>

#include <cubefs/api/models/model.hpp>

namespace cubefs    {
namespace ctr       {

using namespace cubefs::btree;
using namespace cubefs::tools;


template <
        typename ModelTypeName,
        typename KeysType,
        typename ValueType_,
        Int      Indexes_,
        bool     MapType_,
        typename PagesType,
        typename IteratorPartsListType_,
        typename CountersType,
        typename NodeBaseType,
        typename EmbeddedModelsListType,
        typename ModelInterfaceType,
        typename IteratorInterfaceType,
        typename DataPageTypesListType,
        typename ModelTypes
>
struct BTreeModelTypes {
        typedef KeysType                                                        KeysList;
        typedef ValueType_                                                      Value;
        typedef PagesType                                                       Pages;
        typedef IteratorPartsListType_                                          IteratorPartsList;
        typedef CountersType                                                    Counters;
        typedef NodeBaseType                                                    NodeBase;
        typedef EmbeddedModelsListType                                          EmbeddedModelsList;
        typedef ModelInterfaceType                                              ModelInterface;
        typedef IteratorInterfaceType                                           IteratorInterface;
        typedef DataPageTypesListType                                           DataPageTypesList;

        static const Int Indexes                                                = Indexes_;
        static const bool MapType                                               = MapType_;

        template <typename Model>
        struct IteratorFactory {
            typedef typename ModelTypes::template IteratorFactory<Model>::Type Type;
        };

        template <
			typename MyType,
			typename TypesType,
			typename ModelTypeNameType
        >
        struct ModelBaseFactory {
        	typedef typename ModelTypes::template ModelBaseFactory<
				MyType,
				TypesType,
				ModelTypeNameType
			>::Type 															Type;
        };

        template <
			typename MyType,
			typename ModelType
        >
        struct IteratorBaseFactory {
        	typedef typename ModelTypes::template IteratorBaseFactory<
				MyType,
				ModelType
			>::Type 															Type;
        };
};

template <typename Profile_, typename ModelTypeName_, typename ValueType_>
struct BTreeTypes {
    
    typedef ModelTypeName_                                                      ModelTypeName;
    typedef TypeList<BigInt>                                                    KeysListType;
    typedef ValueType_                                                          ValueType;
    static const Int Indexes                                                    = 1;

    static const bool MapType                                                   = MapTypes::Value;

    typedef typename TypeListTool<
                        ToolsName,
                        StubsName,
                        ChecksName,
                        InsertName,
                        RemoveName,
                        FindName
    >::List                                                                     ModelPartsList;

    typedef NullType                                                            BasePagePartsList;
    
    typedef NullType                                                            RootPagePartsList;

    typedef NullType                                                            InternalPagePartsList;

    typedef NullType                                                            LeafPagePartsList;

    typedef NullType                                                            DataPageTypesList;

    typedef typename TypeListTool<
                        IteratorToolsName,
                        IteratorWalkName,
                        IteratorAPIName,
                        IteratorModelAPIName
    >::List                                                                     IteratorPartsList;

    typedef cubefs::api::TreeMapImpl                                            ModelInterfaceName;
    typedef cubefs::api::TreeMapIteratorImpl                                    IteratorInterfaceName;


    template <typename ModelType>
    struct IteratorFactory {
        typedef BTreeIterator<Profile_, ModelType>                              Type;
    };

    template <
		typename MyType_,
		typename TypesType_,
		typename ModelTypeNameType_
    >
    struct ModelBaseFactory {
    	typedef BTreeModelBase<Profile_, MyType_, TypesType_, ModelTypeNameType_>  Type;
    };

    template <
		typename MyType_,
		typename ModelType_
    >
    struct IteratorBaseFactory {
    	typedef BTreeIteratorBase<Profile_, MyType_, ModelType_> 				Type;
    };
};


template <
        typename Profile,
        typename ModelTypes,
        typename DefaultType
>
class TypeFactory<
        RootProfile,
        Profile,
        BTree<
            ModelTypes
        >,
        DefaultType
> {
public:

    typedef typename ModelTypes::ModelTypeName                                  ModelTypeName;

    typedef typename ModelTypes::ModelPartsList                                 ModelPartsList;

    CUBEFS_STATIC_ASSERT(IsList<ModelPartsList>::Value);

    typedef typename ModelTypes::IteratorPartsList                              IteratorPartsList;

    CUBEFS_STATIC_ASSERT(IsList<IteratorPartsList>::Value);

    typedef typename ModelTypes::BasePagePartsList                              BasePagePartsList;

    CUBEFS_STATIC_ASSERT(IsList<BasePagePartsList>::Value);

    typedef typename ModelTypes::RootPagePartsList                              BasicRootPagePartsList;
    CUBEFS_STATIC_ASSERT(IsList<BasicRootPagePartsList>::Value);

    typedef TypeList<
                RootNodeMetadataName<ModelTypeName>,
                BasicRootPagePartsList
    >                                                                           RootPagePartsList;
    

    typedef typename ModelTypes::LeafPagePartsList                              LeafPagePartsList;

    CUBEFS_STATIC_ASSERT(IsList<LeafPagePartsList>::Value);

    typedef typename ModelTypes::InternalPagePartsList                          InternalPagePartsList;

    CUBEFS_STATIC_ASSERT(IsList<InternalPagePartsList>::Value);


    typedef typename ModelTypes::ModelInterfaceName                             ModelInterfaceType;
    typedef typename ModelTypes::IteratorInterfaceName                          IteratorInterfaceType;

    typedef typename ContainerTypesLocator<Profile>::PageManagerType            PageMgr;
    typedef typename PageMgr::Page::ID                                          ID;
    typedef typename PageMgr::Transaction                                       Txn;

    static const Int  IndexCount                                                = ModelTypes::Indexes;
    static const bool MapType                                                   = ModelTypes::MapType;

    typedef typename ModelTypes::KeysListType                                   KeysListType;
    typedef typename ModelTypes::ValueType                                      ValueTypeName;

    typedef typename IfThenElse<
                IfTypesEqual<ValueTypeName, IDType>::Value,
                ID,
                ValueTypeName
    >::Result                                                                   ValueType;

    typedef typename NodeTypeListBuilder <
                Profile,
                ModelTypeName,
                NodePageFactory,
                IndexCount,
                Lists<
                    BasePagePartsList,
                    RootPagePartsList,
                    InternalPagePartsList,
                    LeafPagePartsList
                >,
                KeysListType,
                MapType,
                ValueType,
                typename PageMgr::Page::ID
    >::List                                                                     NodeTypesList;

    CUBEFS_STATIC_ASSERT(IsNonemptyList<NodeTypesList>::Value);

    typedef typename NodeBaseLocator<
                Profile,
                ModelTypeName,
                BasePagePartsList
    >::Type                                                                     NodeBase;


    typedef BTreeModelDispatchersBuilder<
                NodeTypesList,
                NodeBase,
                PageMgr,
                Txn
    >                                                                           PageDispatchers;

    typedef BTreeModelTypes <
                ModelTypeName,
                KeysListType,
                ValueType,
                IndexCount,
                MapType,
                PageDispatchers,
                IteratorPartsList,
                typename CountersLocator<Profile, ModelTypeName>::Type,
                NodeBase,
                NullType,
                ModelInterfaceType,
                IteratorInterfaceType,
                typename ModelTypes::DataPageTypesList,
                ModelTypes
    >                                                                           Types;


public:

    typedef Model<
                ModelTypeName,
                ModelPartsList,
                Types
    >                                                                           Type;
};

}
}


#endif
